/*
 ============================================================================
 Name        : Practica2.c
 Author      : Jorge García
 Version     : 1.0
 Copyright   : Bajo los terminos de la licencia GNU GPL V 3 y posteriores
 Description : Solucion a la practica 2 sobre interacción. Incisos 1, 3, y 3
 ============================================================================
 */

#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>

#define PI 3.141592654

typedef struct {
   float x;
   float y;
   float radio;
   float color[3];
}Circulo;

void inicializa(void);
void dibuja(void);
void tecladoEspecial(int key, int cx, int cy);
void teclado(unsigned char key, int cx, int cy);
void raton(int boton, int estado, int cx, int cy);
void dibujaCirculo(int lados, Circulo c);

/* Variable global para guardar al circulo a dibujar */
Circulo pelota;
/* Variable global para guardar que tanto nos aproximamos al circulo real */
int aproximacion;
/* Variable global para guardar cuentos pixeles nos movemos cada teclazo de direccion */
int deltaPixels;

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(100, 150);
    glutCreateWindow("Interaccion con un circulo");
    inicializa();

    glutDisplayFunc(dibuja);
    glutSpecialFunc(tecladoEspecial);
    glutKeyboardFunc(teclado);
    glutMouseFunc(raton);

    glutMainLoop();
    return 0;
}

void inicializa() {
    glClearColor(0.0, 0.0, 0.0, 1.0);

    /* Color de default del ciculo en rojo */
    pelota.color[0] = 1.0;
    pelota.color[1] = 0.0;
    pelota.color[2] = 0.0;

    /* De default nos intentamos aproximar al circulo con
     * un octagono */
    aproximacion = 8;

    /* De default el circulo esta en el centro y mide 30 pixeles de radio */
    pelota.x = 320;
    pelota.y = 240;
    pelota.radio = 35;

    /* nos movemos 5 pixeles en cada teclazo */
    deltaPixels = 5;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}

void dibuja(void) {

    glClear(GL_COLOR_BUFFER_BIT);

    dibujaCirculo(aproximacion, pelota);

    glFlush();
}


/* Permite mejorar al arpoximacion con las teclas de aumentar y disminuir pagina
 * (el primer inciso de la practica y mover el circulo con las teclas de flecha
 * (el segundo inciso de la practica */

void tecladoEspecial (int key, int cx, int cy) {

	switch(key) {
		case GLUT_KEY_PAGE_UP:
			aproximacion++;
		break;

		case GLUT_KEY_PAGE_DOWN:
			 if (aproximacion > 3) aproximacion--;
		break;

		case GLUT_KEY_UP:
			pelota.y += deltaPixels;
		break;

		case GLUT_KEY_DOWN:
			pelota.y -= deltaPixels;
		break;

		case GLUT_KEY_LEFT:
			pelota.x -= deltaPixels;
		break;

		case GLUT_KEY_RIGHT:
			pelota.x += deltaPixels;
		break;
	}

	glutPostRedisplay();
}

/* Terminemos el programa con la tecla Esc */
void teclado (unsigned char key, int cx, int cy) {
	switch(key) {

		case 27:
			exit(0);
		break;

	}

	glutPostRedisplay();
}

/* Movamos el centro del circulo al punto donde el usuario
 * de un clik (inciso dos de la practica) */
void raton (int boton, int estado, int cx, int cy) {

	if (boton == GLUT_LEFT_BUTTON && estado == GLUT_DOWN) {
		pelota.x = cx;
		pelota.y = 480 - cy;
	}

	glutPostRedisplay();
}

/* Funcion que nos permite dibujar el circulo, dada una aproximacion.
 * Aviso: No valido que lados sea positivo */
void dibujaCirculo(int lados, Circulo c) {
	int i;
	float x[2], angulo = 0.0, deltaAngulo = 2.0 * PI / lados;

	glColor3fv(c.color);
	glBegin(GL_POLYGON);
	for (i = 0; i < lados; i++, angulo += deltaAngulo) {
		x[0] = c.radio * cos(angulo) + c.x;
		x[1] = c.radio * sin(angulo) + c.y;
		glVertex2fv(x);
	}
	glEnd();
}
